﻿using System;
using System.Linq;
using Missbot.Common;
using Missbot.Core.Base;

namespace Missbot.AIModule
{
    /// <summary>
    /// 等待服务
    /// </summary>
    public class WaiterSvc : ISingleton
    {
        /// <summary>
        /// 等待特定的消息
        /// </summary>
        /// <param name="session"></param>
        /// <param name="msg"></param>
        /// <param name="judgeFunc"></param>
        /// <param name="timeout"></param>
        /// <param name="fileID"></param>
        /// <returns></returns>
        public InboxSession WaitForInformation(InboxSession session, string msg, Predicate<InboxSession> judgeFunc, int timeout = 12, string fileID = null)
        {
            session.Channel.Send(session, msg, fileID);
            var msgR = session.Channel.Wait(judgeFunc, timeout);
            return msgR;
        }

        /// <summary>
        /// 等待确认消息
        /// </summary>
        /// <param name="session"></param>
        /// <param name="msg"></param>
        /// <param name="timeout"></param>
        /// <param name="ConfirmTxt"></param>
        /// <param name="CancelTxt"></param>
        /// <returns></returns>
        public bool WaitForConfirm(InboxSession session, string msg, int timeout = 7, string ConfirmTxt = "确认", string CancelTxt = "取消")
        {
            var response = WaitForInformation(session,
                                              $"{msg}\r1：{ConfirmTxt}，2：{CancelTxt}",
                                              information => (session.Group == null || information.Group.ID == session.Group.ID) &&
                                                             information.User.ID == session.User.ID &&
                                                             int.TryParse(information.Text, out var i) &&
                                                             i is 1 or 2,
                                              timeout);
            return response != null && int.TryParse(response.Text, out var ri) && ri == 1;
        }

        /// <summary>
        /// 等待消耗金币确认消息
        /// </summary>
        /// <param name="session"></param>
        /// <param name="golds"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public bool WaitForConfirm_Gold(InboxSession session, int golds, int timeout = 7)
        {
            return WaitForConfirm(session, $"此操作将花费 {golds.CurencyFormat()}，是否继续？", timeout);
        }

        /// <summary>
        /// 等待数字确认消息
        /// </summary>
        /// <param name="session"></param>
        /// <param name="msg"></param>
        /// <param name="predicate"></param>
        /// <param name="timeout"></param>
        /// <param name="fileID"></param>
        /// <returns></returns>
        public int WaitForNum(InboxSession session, string msg, Predicate<int> predicate, int timeout = 12, string fileID = null)
        {
            var msgInfo = WaitForInformation(session, msg,
                                             info => (session.Group == null || info.Group.ID == session.Group.ID) &&
                                                     info.User.ID == session.User.ID &&
                                                     int.TryParse(info.Text, out var res) &&
                                                     predicate(res),
                                             timeout,
                                             fileID);
            if (msgInfo != null && int.TryParse(msgInfo.Text, out var aimr))
            {
                return aimr;
            }

            return -1;
        }

        /// <summary>
        /// 等待选项确认消息
        /// </summary>
        /// <param name="session"></param>
        /// <param name="preMsg"></param>
        /// <param name="options"></param>
        /// <param name="fileID"></param>
        /// <returns></returns>
        public int WaitForOptions(InboxSession session, string preMsg, string[] options, string fileID = null)
        {
            var msg = $"{preMsg}\n{string.Join("\n", options.Select((option, idx) => $"{idx + 1}:{option}"))}";
            var result = WaitForNum(session, msg, i => i > 0 && i <= options.Length, fileID: fileID);
            return result < 0 ? result : result - 1;
        }
    }
}